//@author A0091838U
//This class is for interpreting the DateTime String as a DateTime Object.
package crossoff.datetime;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.LocalTime;

import crossoff.model.Pair;

public class DateTimeHandler {

	private static final int YEAR_TO_ADD = 2000;
	private static final int DEFAULT_YEAR = new LocalDate().getYear();
	private static final int SPECIAL_YEAR_GROUP = 27;
	private static DateTimeHandler datetimehandler = null;

	public static DateTimeHandler getInstance() {
		if (datetimehandler == null) {
			datetimehandler = new DateTimeHandler();
		}
		return datetimehandler;

	}

	/**
	 * This method converts a time string into a Date
	 * 
	 * @param time
	 *            String
	 * @return Date
	 */
	private LocalTime convertTimeStrToDate(String time) {
		if (time == null) {
			assert false;
		}
		Time24HoursValidator TV24 = new Time24HoursValidator();
		Time12HoursValidator TV12 = new Time12HoursValidator();
		if (TV24.validate(time)) {
			return extract24HPattern(time);
		}
		if (TV24.validate1(time)) {
			return extract24HPattern1(time);
		}
		if (TV12.validate(time)) {
			return extract12HPattern(time);
		}
		if (TV12.validate1(time)) {
			return extract12HPattern1(time);
		}
		if (TV12.validate2(time)) {
			return extract12HPattern2(time);
		}
		if (TV12.validate3(time)) {
			return extract12HPattern3(time);
		} else {
			return null;
		}
	}

	private LocalTime extract12HPattern3(String time) {
		int hours = 0;
		int minutes = 0;
		hours = Integer.parseInt(time);
		if (hours == 12) {
			hours = 0;
		}
		minutes = 0;
		return new LocalTime(hours, minutes);
	}

	private LocalTime extract12HPattern2(String time) {
		int hours = 0;
		int minutes = 0;
		hours = Integer.parseInt(time.substring(0, 2));
		minutes = Integer.parseInt(time.substring(2, 4));
		String zone = time.substring(4);
		hours = validateZoneInfo(hours, zone);
		return new LocalTime(hours, minutes);
	}

	private LocalTime extract12HPattern1(String time) {
		if (time.contains(" ")) {
			return extractWithSpace(time);
		} else {
			return extractWithoutSpace(time);
		}
	}

	private LocalTime extract12HPattern(String time) {
		String[] valArray;
		int hours = 0;
		int minutes = 0;
		valArray = time.split(":");
		hours = Integer.parseInt(valArray[0]);
		String minute = valArray[1].substring(0, 2);
		minutes = Integer.parseInt(minute);
		String zone = valArray[1].substring(2);
		hours = validateZoneInfo(hours, zone);
		return new LocalTime(hours, minutes);
	}

	private LocalTime extractWithoutSpace(String time) {
		int hours;
		String zone;
		zone = time.substring(time.length() - 2, time.length());
		hours = Integer.parseInt(time.substring(0, time.length() - 2));
		hours = validateZoneInfo(hours, zone);
		return new LocalTime(hours, 0);
	}

	private LocalTime extractWithSpace(String time) {
		String[] valArray;
		int hours;
		String zone;
		valArray = time.split(" ");
		hours = Integer.parseInt(valArray[0]);
		zone = valArray[1];
		hours = validateZoneInfo(hours, zone);
		return new LocalTime(hours, 0);
	}

	private int validateZoneInfo(int hours, String zone) {
		if (zone.contains("pm") && hours != 12) {
			hours = hours + 12;
		}
		if (zone.contains("am") && hours == 12) {
			hours = hours - 12;
		}
		return hours;
	}

	private LocalTime extract24HPattern1(String time) {
		int hours = 0;
		int minutes = 0;
		hours = Integer.parseInt(time.substring(0, 2));
		minutes = Integer.parseInt(time.substring(2, 4));
		return new LocalTime(hours, minutes);
	}

	private LocalTime extract24HPattern(String time) {
		String[] valArray;
		int hours = 0;
		int minutes = 0;
		valArray = time.split(":");
		hours = Integer.parseInt(valArray[0]);
		minutes = Integer.parseInt(valArray[1]);
		return new LocalTime(hours, minutes);
	}

	/**
	 * This method converts a date String to a Date
	 * 
	 * @param date
	 *            String
	 * @return Date
	 */
	private LocalDate convertDateStrToDate(String date) {
		if (date == null) {
			assert false;
		}
		DateValidator DV = new DateValidator();
		if (DV.validate(date)) {
			return extractDatePattern(date, DV);
		}
		if (DV.validate1(date)) {
			return extractDatePattern1(date, DV);
		}

		if (DV.validate2(date)) {
			return extractDatePattern2(date, DV);
		}
		if (DV.validate3(date)) {
			return extractDatePattern3(date, DV);
		}

		if (DV.validate4(date)) {
			return extractDatePattern4(date, DV);
		}
		if (DV.validate5(date)) {
			return extractDatePattern5(date, DV);
		}

		if (DV.validate6(date)) {
			return extractDatePattern6(date, DV);
		}
		if (DV.validate7(date)) {
			return extractDatePattern7(date, DV);
		}

		if (DV.validate8(date)) {
			return extractDatePattern8(date, DV);
		}
		if (DV.validate9(date)) {
			return extractDatePattern9(date, DV);
		}
		if (DV.validate10(date)) {
			return extractDatePattern10(date, DV);
		}
		if (DV.validate11(date)) {
			return extractDatePattern11(date, DV);
		}
		if (DV.validate12(date)) {
			return extractDatePattern12(date, DV);
		}
		if (DV.validate13(date)) {
			return extractDatePattern13(date, DV);
		}
		if (DV.validate14(date)) {
			return extractDatePattern14(date, DV);
		}
		if (DV.validate15(date)) {
			return extractDatePattern15(date, DV);
		}
		if (DV.validate16(date)) {
			return extractDatePattern16(date, DV);
		}
		if (DV.validate17(date)) {
			return extractDatePattern17(date, DV);
		}
		if (date.equalsIgnoreCase("today")) {
			LocalDate today = new LocalDate();
			int _date = today.getDayOfMonth();
			int _month = today.getMonthOfYear();
			int _year = today.getYear();
			return new LocalDate(_year, _month, _date);
		}
		if (date.equalsIgnoreCase("tomorrow") || date.equalsIgnoreCase("Tmr")) {
			LocalDate today = new LocalDate();
			return today.plusDays(1);
		}
		if (date.equalsIgnoreCase("day after tomorrow")
				|| date.equalsIgnoreCase("day after tmr")
				|| date.equalsIgnoreCase("the day after tomorrow")
				|| date.equalsIgnoreCase("the day after tmr")) {
			LocalDate today = new LocalDate();
			return today.plusDays(2);
		}
		if (isNextMonday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 8 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisMonday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 1 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}
		if (isNextTuesday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 9 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisTuesday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 2 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}
		if (isNextWednesday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 10 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisWednesday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 3 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}
		if (isNextThursday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 11 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisThursday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 4 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}
		if (isNextFriday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 12 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisFriday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 5 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}
		if (isNextSaturday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 13 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisSaturday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 6 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}
		if (isNextSunday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 7 - _day;
			return today.plusDays(day_diff);

		}
		if (isThisSunday(date)) {
			LocalDate today = new LocalDate();
			int _day = today.getDayOfWeek();
			_day = updateDayOfSunday(_day);
			int day_diff = 0 - _day;
			day_diff = updateDayDiff_ThisWeek(day_diff);
			return today.plusDays(day_diff);
		}

		return null;
	}

	private int updateDayOfSunday(int _day) {
		if (_day == 7)
			return 0;
		return _day;
	}

	private boolean isThisSunday(String date) {
		return date.equalsIgnoreCase("sunday") || date.equalsIgnoreCase("sun");
	}

	private boolean isNextSunday(String date) {
		return date.equalsIgnoreCase("next sunday")
				|| date.equalsIgnoreCase("next sun");
	}

	private boolean isThisSaturday(String date) {
		return date.equalsIgnoreCase("saturday")
				|| date.equalsIgnoreCase("sat");
	}

	private boolean isNextSaturday(String date) {
		return date.equalsIgnoreCase("next saturday")
				|| date.equalsIgnoreCase("next sat");
	}

	private boolean isThisFriday(String date) {
		return date.equalsIgnoreCase("friday") || date.equalsIgnoreCase("fri");
	}

	private boolean isNextFriday(String date) {
		return date.equalsIgnoreCase("next friday")
				|| date.equalsIgnoreCase("next fri");
	}

	private boolean isThisThursday(String date) {
		return date.equalsIgnoreCase("thursday")
				|| date.equalsIgnoreCase("thur");
	}

	private boolean isNextThursday(String date) {
		return date.equalsIgnoreCase("next thursday")
				|| date.equalsIgnoreCase("next thur");
	}

	private boolean isThisWednesday(String date) {
		return date.equalsIgnoreCase("wednesday")
				|| date.equalsIgnoreCase("wed");
	}

	private boolean isNextWednesday(String date) {
		return date.equalsIgnoreCase("next wednesday")
				|| date.equalsIgnoreCase("next wed");
	}

	private boolean isThisTuesday(String date) {
		return date.equalsIgnoreCase("tuesday") || date.equalsIgnoreCase("tue");
	}

	private boolean isNextTuesday(String date) {
		return date.equalsIgnoreCase("next tuesday")
				|| date.equalsIgnoreCase("next tue");
	}

	private boolean isThisMonday(String date) {
		return date.equalsIgnoreCase("monday") || date.equalsIgnoreCase("mon");
	}

	private boolean isNextMonday(String date) {
		return date.equalsIgnoreCase("next monday")
				|| date.equalsIgnoreCase("next mon");
	}

	private int updateDayDiff_ThisWeek(int day_diff) {
		if (day_diff <= 0) {
			day_diff = day_diff + 7;
		}
		return day_diff;
	}

	private LocalDate extractDatePattern17(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern17();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern16(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern16();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern15(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern15();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern14(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern14();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern13(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern13();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern12(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern12();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern11(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern11();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = Integer.parseInt(matcher.group(SPECIAL_YEAR_GROUP));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern10(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern10();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = Integer.parseInt(matcher.group(SPECIAL_YEAR_GROUP));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern9(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern9();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = Integer.parseInt(matcher.group(SPECIAL_YEAR_GROUP));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern8(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern8();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = Integer.parseInt(matcher.group(SPECIAL_YEAR_GROUP));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern7(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern7();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = Integer.parseInt(matcher.group(SPECIAL_YEAR_GROUP));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern6(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern6();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = MonthConverter(matcher.group(2));
		year = Integer.parseInt(matcher.group(SPECIAL_YEAR_GROUP));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern5(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern5();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern4(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern4();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = DEFAULT_YEAR;
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern3(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern3();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = Integer.parseInt(matcher.group(3));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern2(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern2();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = Integer.parseInt(matcher.group(3));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern1(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern1();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = Integer.parseInt(matcher.group(3));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private LocalDate extractDatePattern(String date, DateValidator DV) {
		Pattern pattern;
		Matcher matcher;
		int year, monthOfYear, dayOfMonth;
		pattern = DV.getPattern0();
		matcher = pattern.matcher(date);
		matcher.find();
		dayOfMonth = Integer.parseInt(matcher.group(1));
		monthOfYear = Integer.parseInt(matcher.group(2));
		year = Integer.parseInt(matcher.group(3));
		year = updateToYear(year);
		return new LocalDate(year, monthOfYear, dayOfMonth);
	}

	private int updateToYear(int year) {
		if (year < 100) {
			year = year + YEAR_TO_ADD;
		}
		return year;
	}

	public LocalDate figureOutCurrentDate(LocalTime inputTime) {

		LocalTime now = new LocalTime();
		LocalDate today = new LocalDate();

		if (now.compareTo(inputTime) > 0) {

			return today.plusDays(1);
		}

		else {

			return today;
		}
	}

	private int MonthConverter(String month) {
		if (month.equalsIgnoreCase("Jan") || month.equalsIgnoreCase("January"))
			return 1;
		if (month.equalsIgnoreCase("Feb") || month.equalsIgnoreCase("February"))
			return 2;
		if (month.equalsIgnoreCase("Mar") || month.equalsIgnoreCase("March"))
			return 3;
		if (month.equalsIgnoreCase("Apr") || month.equalsIgnoreCase("April"))
			return 4;
		if (month.equalsIgnoreCase("May"))
			return 5;
		if (month.equalsIgnoreCase("Jun") || month.equalsIgnoreCase("June"))
			return 6;
		if (month.equalsIgnoreCase("Jul") || month.equalsIgnoreCase("July"))
			return 7;
		if (month.equalsIgnoreCase("Aug") || month.equalsIgnoreCase("August"))
			return 8;
		if (month.equalsIgnoreCase("Sep")
				|| month.equalsIgnoreCase("September"))
			return 9;
		if (month.equalsIgnoreCase("Oct") || month.equalsIgnoreCase("October"))
			return 10;
		if (month.equalsIgnoreCase("Nov") || month.equalsIgnoreCase("November"))
			return 11;
		if (month.equalsIgnoreCase("Dec") || month.equalsIgnoreCase("December"))
			return 12;
		else {
			return 0;
		}
	}

	// Integer of the pair refers to number of words that the time took up.
	public Pair<LocalTime, Integer> evaluateTimeStr(String[] commandSplit,
			int pos) {
		int numWords = 0;
		LocalTime finalTime = null;
		LocalTime tempTime = null;
		int finalPos = 0;
		StringBuilder builder = new StringBuilder();
		while (pos < commandSplit.length && numWords < 2) {
			builder.append(commandSplit[pos]);
			tempTime = convertTimeStrToDate(builder.toString());
			if (tempTime != null) {
				finalTime = tempTime;
				finalPos = numWords + 1;
			}
			pos++;
			numWords++;
			builder.append(" ");
		}
		return new Pair<LocalTime, Integer>(finalTime, finalPos);
	}

	// Integer of the pair refers to number of words that the date took up.
	public Pair<LocalDate, Integer> evaluateDateStr(String[] commandSplit,
			int pos) {
		int numWords = 0;
		LocalDate finalDate = null;
		LocalDate tempDate = null;
		int finalPos = 0;
		StringBuilder builder = new StringBuilder();
		while (pos < commandSplit.length && numWords < 4) {
			builder.append(commandSplit[pos]);
			tempDate = convertDateStrToDate(builder.toString());
			if (tempDate != null) {
				finalDate = tempDate;
				finalPos = numWords + 1;
			}
			pos++;
			numWords++;
			builder.append(" ");
		}
		return new Pair<LocalDate, Integer>(finalDate, finalPos);
	}

	public Pair<DateTime, Integer> evaluateDateTimeStr(String[] commandSplit,
			int pos) {
		LocalDate date = null;
		LocalTime time = null;
		int delimitPoint = 0;
		Pair<LocalDate, Integer> tempDatePair;
		Pair<LocalTime, Integer> tempTimePair;
		int counter = 0;
		while (date == null && counter < 3
				&& commandSplit.length >= pos + counter + 1) {
			tempDatePair = evaluateDateStr(commandSplit, pos + counter);
			date = tempDatePair.getFirst();
			delimitPoint = tempDatePair.getSecond();
			counter++;
		}
		if (date == null) {
			return null;
		} else if (counter == 1) {
			tempTimePair = evaluateTimeStr(commandSplit, pos + delimitPoint);
			time = tempTimePair.getFirst();
			delimitPoint += tempTimePair.getSecond();
		} else {
			tempTimePair = evaluateTimeStr(commandSplit, pos);
			time = tempTimePair.getFirst();
			delimitPoint += tempTimePair.getSecond();
			if (isContainsSpecialString(commandSplit, pos, tempTimePair)) {
				delimitPoint += 1;
			}
		}
		if (time == null) {
			return null;
		} else {
			return new Pair<DateTime, Integer>(new DateTime(date.getYear(),
					date.getMonthOfYear(), date.getDayOfMonth(),
					time.getHourOfDay(), time.getMinuteOfHour()), delimitPoint);
		}
	}

	private boolean isContainsSpecialString(String[] commandSplit, int pos,
			Pair<LocalTime, Integer> tempTimePair) {
		return commandSplit[tempTimePair.getSecond() + pos].equals("on")
				|| commandSplit[tempTimePair.getSecond() + pos].equals("by")
				|| commandSplit[tempTimePair.getSecond() + pos].equals("at")
				|| commandSplit[tempTimePair.getSecond() + pos].equals("to");
	}
}
